package com.slf.common;

import com.slf.main.OneDayTaskJob;

import java.io.*;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

/**
 * @Author：时吕发
 * @Package：com.slf.common
 * @Project：jydatafillctp
 * @name：RunJobHandler
 * @Date：2025/9/13 16:55
 * @Filename：RunJobHandler
 * @desc:
 */
public class RunJobHandler {
    private final static Logger logger = LoggerUtil.getLogger("jydatafillctp");

    // 需要补充的时间点列表（从145715000到145945000）
    private static final String[] SUPPLEMENT_TIMES = {
            "145715", "145730", "145745", "145800",
            "145815", "145830", "145845", "145900",
            "145915", "145930", "145945"
    };

    private static final int CAL_T = 60;
    private static int Min_NUM;

    //期货价格map,code,日期_时间,value是价格
    private static Map<String, Map<String, Double>> futuresMap = new HashMap<>();

    public static void runJob(String jyDataFilePath,
                              String ctpHqFilePath,
                              String exportFilePath,
                              String runDate) throws Exception {
        logger.info("*****************开始运行单日任务*****************");
        logger.info("jyDataFilePath: " + jyDataFilePath+ " ctpHqFilePath: " + ctpHqFilePath+ " exportFilePath: " + exportFilePath+ " runDate: " + runDate);

        /*
         1.检查文件路径是否正确
         2.检查各个文件夹中是否有需要的文件
         */
        File jyDataFileDir = new File(jyDataFilePath);
        File ctpHqFileDir = new File(ctpHqFilePath);
        File exportFileDir = new File(exportFilePath);
        //检查上述上个文件夹是否存在
        if (!jyDataFileDir.exists() ||!ctpHqFileDir.exists() ||!exportFileDir.exists()) {
            throw new Exception("文件路径不正确");
        }
        //TODO: 检查各个文件夹中是否有需要的文件
        //检查jyDataFile文件夹中是否有sifhq_min_runDate.csv文件
        File jyDateFile = new File(jyDataFileDir.getAbsolutePath(), "sifhq_min_" + runDate + ".csv");
        if (!jyDateFile.exists()) {
            throw new Exception("sifhq_min_" + runDate + ".csv文件不存在");
        }

        /*检查ctpHqFile文件夹中是否有ctpmd_ic_runDate.csv、ctpmd_im_runDate.csv、
        ctpmd_ih_runDate.csv、ctpmd_if_runDate.csv等4个文件
        */
        File ctpHqFile_ic = new File(ctpHqFilePath, "ctpmd_ic_" + runDate + ".csv");
        File ctpHqFile_im = new File(ctpHqFilePath, "ctpmd_im_" + runDate + ".csv");
        File ctpHqFile_ih = new File(ctpHqFilePath, "ctpmd_ih_" + runDate + ".csv");
        File ctpHqFile_if = new File(ctpHqFilePath, "ctpmd_if_" + runDate + ".csv");
        if (!ctpHqFile_ic.exists() ||!ctpHqFile_im.exists() ||!ctpHqFile_ih.exists() ||!ctpHqFile_if.exists()) {
            throw new Exception("ctpmd_ic_" + runDate + ".csv、ctpmd_im_" + runDate + ".csv、ctpmd_ih_" + runDate + ".csv、ctpmd_if_" + runDate + ".csv文件不存在");
        }
        //检查这些文件是否有数据，若长度小于1kb，则抛出异常
        if(jyDateFile.length() < 1024 || ctpHqFile_ic.length() < 1024 || ctpHqFile_im.length() < 1024 || ctpHqFile_ih.length() < 1024 || ctpHqFile_if.length() < 1024) {
            throw new Exception("文件数据不完整,可能为法定节假日导致数据缺失");
        }
        //TODO: 运行任务
        Map<String, Double> oneDayMap_ih = FuturesDataProcessor.createPriceMap(ctpHqFile_ih.getAbsolutePath(),runDate);
        Map<String, Double> oneDayMap_if = FuturesDataProcessor.createPriceMap(ctpHqFile_if.getAbsolutePath(),runDate);
        Map<String, Double> oneDayMap_ic = FuturesDataProcessor.createPriceMap(ctpHqFile_ic.getAbsolutePath(),runDate);
        Map<String, Double> oneDayMap_im = FuturesDataProcessor.createPriceMap(ctpHqFile_im.getAbsolutePath(),runDate);

        futuresMap.put("IH", oneDayMap_ih);
        futuresMap.computeIfAbsent("IH", k -> new HashMap<>()).putAll(oneDayMap_ih);
        futuresMap.computeIfAbsent("IF", k -> new HashMap<>()).putAll(oneDayMap_if);
        futuresMap.computeIfAbsent("IC", k -> new HashMap<>()).putAll(oneDayMap_ic);
        futuresMap.computeIfAbsent("IM", k -> new HashMap<>()).putAll(oneDayMap_im);

        logger.info("期货数据处理完成");

        //读取分钟数据
        Map<String, List<IndexCollectData>> map = readIndexDataFromDirectory(jyDateFile);
        logger.info("106min数据解析完成");

        //打印结果到文件、
        //打印1分钟1个数据的结果
        Min_NUM = 1;
        printData(map, exportFilePath);
        logger.info("1分钟1个数据的结果输出完成");
        //打印1分钟4个数据的结果
        Min_NUM = 4;
        printData(map, exportFilePath);
        logger.info("1分钟4个数据的结果输出完成");
        logger.info("###############开始运行单日任务###############");
    }

    public static Map<String, List<IndexCollectData>> readIndexDataFromDirectory(File file) {
        Map<String, List<IndexCollectData>> resultMap = new HashMap<>();

            //跳过非交易日,文件大小小于10KB,则跳过
            if (file.length() < 10 * 1024) {
                logger.info(file.getName() + "文件大小小于10KB,当日为节假日,跳过");
                return resultMap;
            }
            try (BufferedReader br = new BufferedReader(new FileReader(file))) {
                String line;

                while ((line = br.readLine()) != null) {
                    IndexCollectData data = parseIndexDataLine(line);
                    if (data == null) {
                        throw new RuntimeException("程序结束,数据行格式错误: " + line);
                    }
                    resultMap.computeIfAbsent(data.getCode(), k -> new ArrayList<>()).add(data);
                    //如果当前时间是145700,则补充当日的11条数据
                    if (data.getTime().equals("145700")) {
                        // 生成并写入11条补充数据
                        for (String newTime : SUPPLEMENT_TIMES) {
                            //补充这段时间的数据，大单和总量都为0
                            IndexCollectData oneData = parseIndexData(newTime, data);
                            resultMap.computeIfAbsent(oneData.getCode(), k -> new ArrayList<>()).add(oneData);
                        }
                    }
                }
            } catch (IOException e) {
                System.err.println("处理文件时出错: " + file.getName() + " - " + e.getMessage());
            }
        return resultMap;
    }

    private static IndexCollectData parseIndexDataLine(String line) {
        String[] fields = line.split(",");
        if (fields.length < 12) {
            System.err.println("数据行字段不足12个: " + line);
            return null;
        }
        // 解析CSV字段
        String code = fields[0].trim();
        // 从datetime字段分离日期和时间 (格式: yyyyMMddHHmmssSS)
        String date = fields[11].substring(0, 8);
        // HHmmss
        String time = fields[1].substring(0, fields[1].length() - 3);

        long bigAmount = Long.parseLong(fields[3].trim());
        long sumAmount = Long.parseLong(fields[4].trim());

        double indexPrice = Double.parseDouble(fields[2].trim());

        double futuresPrice = futuresMap.get(getFutureCode(code)).get( date +"_"+ fillZero(time));//TODO
        double filed1 = 0;
        double filed2 = 0;

        long totalAskAmount = Long.parseLong(fields[8].trim());//盘口总卖单（不含涨跌停）
        long totalBidAmount = Long.parseLong(fields[7].trim());//盘口总买单（不含涨跌停）
        double totalBidRate = (double) totalBidAmount / (totalAskAmount + totalBidAmount);//买入比率

        int isLastTradeDate = isThirdFriday(date);

        int riseNum = 0;//成分股上涨个数
        int fallNum = 0;//成分股下跌个数
        double filed3 = 0;//预留字段

        long bsBigSumAmount = 0; //  // 未使用的字段设为默认值

        IndexCollectData data = new IndexCollectData(code, date, time, bigAmount, sumAmount,
                indexPrice, futuresPrice, filed1, filed2, totalAskAmount, totalBidAmount,
                totalBidRate, isLastTradeDate, riseNum, fallNum, filed3, bsBigSumAmount);
        return data;
    }

    public static int isThirdFriday(String dateStr) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        try {
            LocalDate date = LocalDate.parse(dateStr, formatter);
            return checkThirdFriday(date) ? 1 : 0;
        } catch (DateTimeParseException e) {
            return 0; // 格式错误直接返回0
        }
    }

    private static boolean checkThirdFriday(LocalDate date) {
        // 计算当月的第三个星期五
        LocalDate thirdFriday = date.withDayOfMonth(1) // 当月第一天
                .with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY)) // 第一个星期五
                .plusWeeks(2); // 加两周得到第三个星期五
        return date.isEqual(thirdFriday);
    }

    private static IndexCollectData parseIndexData(String newTime, IndexCollectData data) {
        // 复制原数据
        IndexCollectData newData = new IndexCollectData(data);
        // 修改时间
        newData.setTime(newTime);
        //修改大单和总量
        newData.setBigAmount(0);
        newData.setSumAmount(0);
        // 修改价格
        double futuresPrice = futuresMap.get(getFutureCode(data.getCode())).get( data.getDate() +"_"+ fillZero(newTime));
        newData.setFuturesPrice(futuresPrice);
        // 增加到结果集
        return newData;
    }

    private static String getFutureCode(String code) {
        if (code.equals("000016")) {
            return "IH";
        } else if (code.equals("000300")) {
            return "IF";
        } else if (code.equals("000905")) {
            return "IC";
        } else if (code.equals("000852")) {
            return "IM";
        }
        return null;
    }

    private static void printData(Map<String, List<IndexCollectData>> map,String filePath) {
        if(map==null||map.isEmpty()){
            logger.info("没有数据,不输出文件:map is null or empty");
            return;
        }
        // 便利map,输出文件
        for (String code : map.keySet()) {
            List<IndexCollectData> indexCollectDataList = map.get(code);
            if (indexCollectDataList.isEmpty()) {
                logger.info("没有数据,不输出文件:indexCollectDataList is null or empty");
                continue;
            }
            if(indexCollectDataList.size()!=961){
                logger.info("数据异常,code:" + code + " size:" + indexCollectDataList.size());
            }
            //文件名是list中第一个数据的日期_最后一个数据的日期
            String fileName = "sifhq_"+getFutureCode(code).toLowerCase()+"_"+indexCollectDataList.get(0).getDate()+ ".csv";
            //输出文件
            printStockCollectData2Csv(indexCollectDataList, filePath + File.separator + fileName);
        }
    }

    private static void printStockCollectData2Csv(List<IndexCollectData> indexCollectDataList, String fileName) {
        BufferedWriter bw = null;
        try {
            bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName)));
            for (IndexCollectData d : indexCollectDataList) {
                //只打印整分钟点的数据
                if(Min_NUM==1 && (!d.getTime().endsWith("00"))){
                    continue;
                }
                StringBuilder sb = new StringBuilder();
                sb.append(d.getDate()).append(",").
                        append(d.getTime()).append(",").
                        append(d.getBigAmount()).append(",").
                        append(d.getSumAmount()).append(",").
                        append(d.getIndexPrice()).append(",").
                        append(d.getFuturesPrice()).append(",").
                        append(d.getFiled1()).append(",").
                        append(d.getFiled2()).append(",").
                        append(d.getTotalAskAmount()).append(",").
                        append(d.getTotalBidAmount()).append(",").
                        append(d.getTotalBidRate()).append(",").
                        append(d.getIsLastTradeDate()).append(",").
                        append(d.getRiseNum()).append(",").
                        append(d.getFallNum()).append(",").
                        append(d.getFiled3()).append(",").
                        append(d.getBsBigSumAmount()/10000).append(",");

                bw.write(sb.toString());
                bw.newLine();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bw != null) {
                try {
                    bw.flush();
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static String fillZero(String time) {
        if (time.length() == 5) {
            return "0" + time;
        }
        return time;
    }
}
